<template>
  <el-config-provider :locale="zhCn">
  <div class="page">
    <el-card class="top-card">
      <div class="title">活动信息 <el-button type="primary" class="right-btn" @click="goBackToList">返回列表</el-button></div>
      <div class="info">
        <div>名称：{{ activity?.name || '-' }}</div>
        <div>类型：{{ typeName[activity?.activity_type_id || ''] || '-' }}</div>
        <div>时间：{{ formatDate(activity?.time_start) || '-' }} ~ {{ formatDate(activity?.time_end) || '-' }}</div>
        <div>地点：{{ activity?.location_admin || '-' }} / {{ activity?.location_detail || '-' }}</div>
        <div>主办：{{ activity?.organizer || '-' }}</div>
        <div>指标版本：{{ versionLabel || '-' }}</div>
      </div>
    </el-card>

    <el-card class="score-card">
      <div class="title">指标打分</div>
      <div v-if="!activity?.indicator_version_id" class="empty-tip">
        <el-alert title="该活动尚未关联指标体系，请返回列表完成关联后再进入打分。" type="warning" show-icon />
      </div>
      <div v-else class="score-area">
        <div class="actions">
          <el-button type="primary" @click="computeTotal" :loading="computing">计算总分</el-button>
          <el-button @click="oneClickFullScore" :loading="autoScoring">一键打分</el-button>
          <el-button type="success" @click="autoCollectAndScore" :loading="autoNVLoading">自动采集并打分</el-button>
          <el-button @click="openNVEvidence">查看采集结果</el-button>
          <el-button @click="openNVConfig">采集配置</el-button>
          <div class="right-actions">
            <span class="total">当前总分：{{ totalDisplay }}</span>
            <el-button type="danger" @click="clearAllScores" :loading="clearing">清空打分</el-button>
          </div>
        </div>
        <el-tabs v-model="activeCategory" type="card">
          <el-tab-pane label="基本" name="basic" />
          <el-tab-pane label="扣分" name="deduct" />
          <el-tab-pane label="否决" name="veto" />
        </el-tabs>
        <div class="score-scroll">
          <div v-for="dim in filteredTree" :key="dim.id" class="dimension">
            <div class="dim-title">{{ dim.name }}</div>
            <div class="themes">
              <div v-for="th in dim.themes" :key="th.id" class="theme">
                <div class="theme-title">{{ th.name }}</div>
                <el-table :data="th.items" style="width:100%">
                  <el-table-column prop="code" label="编码" width="120" />
                  <el-table-column prop="name" label="指标项" min-width="220" />
                  <el-table-column prop="criteria" label="评定标准" min-width="260" show-overflow-tooltip />
                  <el-table-column label="上限" width="120">
                    <template #default="{ row }">
                      <span v-if="row.category==='basic'">{{ row.weight ?? '-' }}</span>
                      <span v-else-if="row.category==='deduct'">{{ row.deduct_value ?? '-' }}</span>
                      <span v-else>否决</span>
                    </template>
                  </el-table-column>
                  <el-table-column label="打分" width="220">
                    <template #default="{ row }">
                      <template v-if="row.category==='basic'">
                        <el-input-number v-model="row.input" :min="0" :max="row.weight ?? 0" :step="0.5" @change="val=>onScore(row, val)" />
                      </template>
                      <template v-else-if="row.category==='deduct'">
                        <el-input-number v-model="row.input" :min="row.deduct_value != null ? -Number(row.deduct_value) : -999" :max="0" :step="0.5" @change="val=>onScore(row, val)" />
                      </template>
                      <template v-else>
                        <el-switch v-model="row.veto" @change="val=>onScore(row, 0, Boolean(val))" />
                      </template>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </div>
          </div>
        </div>
      </div>
    </el-card>
  </div>
  </el-config-provider>
  <el-dialog v-model="nvDialog" title="网络声量采集结果" width="680px">
    <div class="nv-agg">
      <div>媒体家数：{{ nvAgg.media_unique_outlets ?? '-' }}</div>
      <div>报道篇数：{{ nvAgg.media_report_count ?? '-' }}</div>
      <div>社交累计互动：{{ nvAgg.social_total_interactions ?? '-' }}</div>
      <div>热度趋势：{{ nvAgg.index_growth_rate ?? '-' }}</div>
    </div>
    <el-divider />
    <div>证据：</div>
    <el-table :data="nvEvidence" style="width:100%">
      <el-table-column prop="type" label="类型" width="120" />
      <el-table-column prop="path_or_url" label="地址" />
      <el-table-column prop="captured_at" label="时间" width="180" />
    </el-table>
    <el-divider />
    <div>平台细分：</div>
    <el-table :data="nvPlatformRows" style="width:100%">
      <el-table-column prop="platform" label="平台" width="160" />
      <el-table-column prop="interactions" label="累计互动" />
    </el-table>
    <el-divider />
    <div style="display:flex;align-items:center;gap:12px;">
      <el-select v-model="trendSource" placeholder="选择趋势来源" style="width:180px">
        <el-option label="微博" value="weibo" />
        <el-option label="抖音" value="douyin" />
      </el-select>
      <el-input v-model="trendKeyword" placeholder="关键词（默认用活动名称）" style="width:240px" />
      <el-button @click="loadTrend">加载趋势</el-button>
      <div>增长率：{{ (trendGrowth*100).toFixed(1) }}%</div>
    </div>
    <SimpleTrendChart :series="trendSeries" :width="640" :height="200" />
    <template #footer>
      <el-button @click="nvDialog=false">关闭</el-button>
    </template>
  </el-dialog>
  <el-dialog v-model="nvConfDialog" title="网络声量采集配置" width="680px">
    <div class="nv-conf">
      <div class="conf-row">
        <div class="conf-label">关键词（逗号分隔）</div>
        <el-input v-model="confKeywords" type="textarea" :rows="3" placeholder="示例：活动名, 别名, 话题标签" />
      </div>
      <div class="conf-row">
        <div class="conf-label">微博账号（逗号分隔）</div>
        <el-input v-model="confWeibo" placeholder="示例：weibo_id1,weibo_id2" />
      </div>
      <div class="conf-row">
        <div class="conf-label">抖音账号（逗号分隔）</div>
        <el-input v-model="confDouyin" placeholder="示例：douyin_id1,douyin_id2" />
      </div>
      <div class="conf-row">
        <div class="conf-label">快手账号（逗号分隔）</div>
        <el-input v-model="confKuaishou" placeholder="示例：kuaishou_id1,kuaishou_id2" />
      </div>
      <div class="conf-row">
        <div class="conf-label">小红书账号（逗号分隔）</div>
        <el-input v-model="confXhs" placeholder="示例：xhs_id1,xhs_id2" />
      </div>
      <div class="conf-row">
        <div class="conf-label">微信账号（逗号分隔）</div>
        <el-input v-model="confWechat" placeholder="示例：mp_id1,mp_id2" />
      </div>
    </div>
    <template #footer>
      <el-button @click="nvConfDialog=false">取消</el-button>
      <el-button type="primary" @click="saveNVConfig">保存</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import { ElMessageBox } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { api } from '../../api/client'
import SimpleTrendChart from '../../components/SimpleTrendChart.vue'

type Activity = {
  id: string
  name: string
  activity_type_id: string
  time_start?: string | null
  time_end?: string | null
  location_admin: string
  location_detail: string
  organizer: string
  indicator_version_id?: string | null
}

type DictItem = { id: string; code: string; name: string }
type IndicatorVersion = { id: string; version_code: string; name: string }
type ItemRow = { id: string; code: string; name: string; category: string; weight?: number|null; deduct_value?: number|null; criteria?: string|null; input?: number|null; veto?: boolean }

const route = useRoute()
const activityId = String(route.params.activityId || '')

const activity = ref<Activity | null>(null)
const typeName = ref<Record<string, string>>({})
const versionLabel = ref('')
const total = ref<number | null>(null)
const computing = ref(false)
const autoScoring = ref(false)
const autoNVLoading = ref(false)
const clearing = ref(false)
const nvDialog = ref(false)
const nvAgg = reactive<any>({})
const nvEvidence = ref<any[]>([])
const nvPlatformRows = ref<any[]>([])
const trendSource = ref<'weibo'|'douyin'>('weibo')
const trendSeries = ref<{ timestamp?: string; value: number }[]>([])
const trendGrowth = ref(0)
const trendKeyword = ref('')
const nvConfDialog = ref(false)
const confKeywords = ref('')
const confWeibo = ref('')
const confDouyin = ref('')
const confKuaishou = ref('')
const confXhs = ref('')
const confWechat = ref('')
const evaluationId = ref<string | null>(null)
const activeCategory = ref<'basic'|'deduct'|'veto'>('basic')
const totalDisplay = computed(() => {
  const hasVeto = tree.value.some(d => d.themes.some(th => th.items.some(it => it.category==='veto' && it.veto)))
  if (hasVeto) return '否决'
  return typeof total.value === 'number' ? Number(total.value.toFixed(2)) : '-'
})

const tree = ref<{ id: string; name: string; themes: { id: string; name: string; items: ItemRow[] }[] }[]>([])
const filteredTree = computed(() => {
  const res: { id: string; name: string; themes: { id: string; name: string; items: ItemRow[] }[] }[] = []
  for (const d of tree.value) {
    const themes: { id: string; name: string; items: ItemRow[] }[] = []
    for (const th of d.themes) {
      const items = th.items.filter(i => i.category === activeCategory.value)
      if (items.length) themes.push({ id: th.id, name: th.name, items })
    }
    if (themes.length) res.push({ id: d.id, name: d.name, themes })
  }
  return res
})

async function loadActivity() {
  const { data } = await api.get(`/activities/${activityId}`)
  activity.value = data
}

async function loadTypeDict() {
  try {
    const { data } = await api.get('/dictionaries/items', { params: { type_code: 'activity_type', page_size: 200 } })
    const m: Record<string, string> = {}
    data.forEach((d: DictItem) => { m[d.id] = d.name })
    typeName.value = m
  } catch {}
}

async function loadTrend() {
  try {
    const { data } = await api.get(`/network-volume/activities/${activityId}/trend`, { params: { source: trendSource.value, keyword: trendKeyword.value || undefined } })
    trendSeries.value = (data.series || []).map((x: any) => ({ timestamp: x.timestamp, value: Number(x.value || 0) }))
    trendGrowth.value = Number(data.growth_rate || 0)
  } catch {}
}

async function loadVersionLabel() {
  if (!activity.value?.indicator_version_id) { versionLabel.value = '' ; return }
  try {
    const { data } = await api.get('/indicators/versions')
    const v = (data as IndicatorVersion[]).find(x => x.id === activity.value!.indicator_version_id)
    versionLabel.value = v ? `${v.name} (${v.version_code})` : ''
  } catch {}
}

async function ensureEvaluation() {
  const { data } = await api.post('/evaluations/upsert', { activity_id: activityId, version_no: 1 })
  evaluationId.value = data.id
}

async function loadTree() {
  if (!activity.value?.indicator_version_id) return
  const { data: dims } = await api.get('/indicators/dimensions', { params: { version_id: activity.value.indicator_version_id } })
  const result: any[] = []
  for (const d of dims) {
    const { data: themes } = await api.get('/indicators/themes', { params: { dimension_id: d.id } })
    const themeList: any[] = []
    for (const t of themes) {
      const { data: items } = await api.get('/indicators/items', { params: { theme_id: t.id } })
      const rows: ItemRow[] = items.map((x: any) => ({ id: x.id, code: x.code, name: x.name, category: x.category, weight: x.weight, deduct_value: x.deduct_value, criteria: x.criteria, input: null, veto: false }))
      themeList.push({ id: t.id, name: t.name, items: rows })
    }
    result.push({ id: d.id, name: d.name, themes: themeList })
  }
  tree.value = result
}

async function loadScores() {
  if (!evaluationId.value) return
  const { data } = await api.get(`/evaluations/${evaluationId.value}/scores`)
  const map: Record<string, any> = {}
  for (const s of data) { map[s.code] = s }
  for (const d of tree.value) {
    for (const th of d.themes) {
      for (const row of th.items) {
        const s = map[row.code]
        if (s) {
          if (row.category === 'basic') { row.input = typeof s.score_value === 'number' ? Number(s.score_value) : null }
          else if (row.category === 'deduct') { row.input = typeof s.score_value === 'number' ? Number(s.score_value) : null }
          else { row.veto = Boolean(s.is_veto) }
        }
      }
    }
  }
  recalcCurrentTotal()
}

async function onScore(row: ItemRow, val?: number|null, veto?: boolean) {
  if (!evaluationId.value) await ensureEvaluation()
  const payload: any = { evaluation_id: evaluationId.value, code: row.code }
  if (row.category === 'veto') { payload.is_veto = Boolean(veto) ; row.veto = Boolean(veto) ; payload.score_value = 0 }
  else if (row.category === 'deduct') { payload.is_veto = false ; payload.score_value = typeof val === 'number' ? Number(val) : 0 ; row.input = payload.score_value }
  else { payload.is_veto = false ; payload.score_value = typeof val === 'number' ? Number(val) : 0 ; row.input = payload.score_value }
  await api.post(`/evaluations/${evaluationId.value}/scores`, payload)
  recalcCurrentTotal()
}

async function computeTotal() {
  if (!evaluationId.value) await ensureEvaluation()
  computing.value = true
  try {
    const { data } = await api.post(`/evaluations/${evaluationId.value}/compute-total`)
    total.value = data.score_total
  } finally { computing.value = false }
}

async function oneClickFullScore() {
  if (!evaluationId.value) await ensureEvaluation()
  autoScoring.value = true
  try {
    const reqs: Promise<any>[] = []
    for (const d of tree.value) {
      for (const th of d.themes) {
        for (const it of th.items) {
          if (it.category === 'basic' && typeof it.weight === 'number') {
            const val = Number(it.weight)
            it.input = val
            const payload: any = { evaluation_id: evaluationId.value, code: it.code, score_value: val, is_veto: false }
            reqs.push(api.post(`/evaluations/${evaluationId.value}/scores`, payload))
          }
        }
      }
    }
    if (reqs.length) await Promise.all(reqs)
    recalcCurrentTotal()
    await computeTotal()
  } finally {
    autoScoring.value = false
  }
}

async function autoCollectAndScore() {
  if (!evaluationId.value) await ensureEvaluation()
  autoNVLoading.value = true
  try {
    await api.post(`/network-volume/activities/${activityId}/collect`)
    await api.post(`/network-volume/evaluations/${evaluationId.value}/auto-score`)
    await loadScores()
    await computeTotal()
  } finally {
    autoNVLoading.value = false
  }
}

async function openNVEvidence() {
  nvDialog.value = true
  try {
    const { data: agg } = await api.get(`/network-volume/activities/${activityId}/aggregates`)
    nvAgg.media_unique_outlets = agg.media_unique_outlets
    nvAgg.media_report_count = agg.media_report_count
    nvAgg.social_total_interactions = agg.social_total_interactions
    nvAgg.index_growth_rate = agg.index_growth_rate
    nvPlatformRows.value = []
    const details = agg.details || {}
    for (const k of Object.keys(details)) {
      nvPlatformRows.value.push({ platform: k, interactions: details[k] })
    }
    const { data: ev } = await api.get(`/network-volume/activities/${activityId}/evidence`)
    nvEvidence.value = ev.items || []
  } catch {}
}

async function openNVConfig() {
  nvConfDialog.value = true
  try {
    const { data } = await api.get(`/network-volume/activities/${activityId}/config`)
    const ks = data.keywords_json ? JSON.parse(data.keywords_json) : []
    const acc = data.accounts_json ? JSON.parse(data.accounts_json) : {}
    confKeywords.value = Array.isArray(ks) ? ks.join(',') : ''
    confWeibo.value = Array.isArray(acc?.weibo) ? acc.weibo.join(',') : ''
    confDouyin.value = Array.isArray(acc?.douyin) ? acc.douyin.join(',') : ''
    confKuaishou.value = Array.isArray(acc?.kuaishou) ? acc.kuaishou.join(',') : ''
    confXhs.value = Array.isArray(acc?.xhs) ? acc.xhs.join(',') : ''
    confWechat.value = Array.isArray(acc?.wechat) ? acc.wechat.join(',') : ''
  } catch {}
}

async function saveNVConfig() {
  try {
    const keywords = confKeywords.value.split(',').map(s => s.trim()).filter(Boolean)
    const accounts = {
      weibo: confWeibo.value.split(',').map(s => s.trim()).filter(Boolean),
      douyin: confDouyin.value.split(',').map(s => s.trim()).filter(Boolean),
      kuaishou: confKuaishou.value.split(',').map(s => s.trim()).filter(Boolean),
      xhs: confXhs.value.split(',').map(s => s.trim()).filter(Boolean),
      wechat: confWechat.value.split(',').map(s => s.trim()).filter(Boolean),
    }
    await api.post(`/network-volume/activities/${activityId}/config`, { keywords, accounts })
    nvConfDialog.value = false
  } catch {}
}

async function clearAllScores() {
  if (!evaluationId.value) await ensureEvaluation()
  try {
    await ElMessageBox.confirm('将删除此活动评估下所有打分信息，包含基本、扣分和否决。', '确认清空', { type: 'warning', confirmButtonText: '确定', cancelButtonText: '取消' })
  } catch {
    return
  }
  clearing.value = true
  try {
    await api.delete(`/evaluations/${evaluationId.value}/scores`)
    for (const d of tree.value) {
      for (const th of d.themes) {
        for (const it of th.items) {
          if (it.category === 'veto') { it.veto = false } else { it.input = null }
        }
      }
    }
    total.value = null
  } finally {
    clearing.value = false
  }
}

function formatDate(v: string | null | undefined): string {
  if (!v) return ''
  const s = String(v)
  if (s.length >= 10) return s.slice(0, 10)
  return s
}

const router = useRouter()
function goBackToList() {
  router.push('/admin/activity-scoring')
}

function recalcCurrentTotal() {
  const hasVeto = tree.value.some(d => d.themes.some(th => th.items.some(it => it.category==='veto' && it.veto)))
  if (hasVeto) { total.value = null ; return }
  let sum = 0
  for (const d of tree.value) {
    for (const th of d.themes) {
      for (const it of th.items) {
        if (it.category === 'basic') {
          if (typeof it.input === 'number') sum += Number(it.input)
        } else if (it.category === 'deduct') {
          if (typeof it.input === 'number') sum += Number(it.input)
        }
      }
    }
  }
  total.value = Number(sum.toFixed(2))
}

onMounted(async () => {
  await Promise.all([loadActivity(), loadTypeDict()])
  await loadVersionLabel()
  if (activity.value?.indicator_version_id) {
    await ensureEvaluation()
    await loadTree()
    await loadScores()
  }
})
</script>

<style scoped>
.page { height: 100%; display: flex; flex-direction: column; padding: 12px 16px; box-sizing: border-box; }
.top-card { margin-bottom: 12px; }
.right-btn { float: right; }
.title { font-weight: 600; margin-bottom: 8px; }
.info { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 12px; }
.score-card { flex: 1; display: flex; flex-direction: column; }
.score-card :deep(.el-card__body) { display: flex; flex-direction: column; min-height: 0; }
.score-area { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.score-scroll { flex: 1; min-height: 0; overflow-y: auto; padding-right: 8px; padding-bottom: 16px; }
.actions { margin-bottom: 12px; display: flex; align-items: center; gap: 12px; }
.total { color: var(--el-color-primary); }
.right-actions { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.dimension { margin-bottom: 16px; background: #f9fbff; border-left: 3px solid var(--el-color-primary); padding: 8px 12px; border-radius: 8px; }
.dim-title { font-weight: 600; margin-bottom: 8px; }
.theme { margin-bottom: 8px; border: 1px solid #ebeef5; border-radius: 8px; padding: 8px; }
.theme-title { font-weight: 500; margin-bottom: 6px; }
.nv-agg { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 12px; margin-bottom: 8px; }
.nv-conf { display: grid; grid-template-columns: 1fr; gap: 12px; }
.conf-row { display: grid; grid-template-columns: 160px 1fr; gap: 12px; align-items: center; }
.conf-label { color: #666; }
</style>
